﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.ComponentModel;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Security.Cryptography;
using System.Reflection;

using Web7.ComponentModel;

namespace Web7
{
    public class CommonHelper
    {
        /// <summary>
        /// 验证一个email
        /// </summary>
        /// <param name="email">要验证的email字符串</param>
        /// <returns>如果正确返回 true 否则返回 false</returns>
        public static bool IsValidEmail(string email)
        {
            if (!String.IsNullOrEmpty(email))
            {
                email = email.Trim();
                var result = Regex.IsMatch(email,
                                            @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$");
                return result;
            }
            return false;
        }

        /// <summary>
        /// 产生随机数
        /// </summary>
        /// <param name="length">长度</param>
        /// <returns>返回随机数</returns>
        public static string GenerateRandomDigitCode(int length)
        {
            var random = new Random();
            string str = string.Empty;
            for (int i = 0; i < length; i++)
                str = String.Concat(str, random.Next(10).ToString(CultureInfo.InvariantCulture));
            return str;
        }

        /// <summary>
        /// 返回一个在指定范围内的随机整型数字
        /// </summary>
        /// <param name="min">最小数字</param>
        /// <param name="max">最大数字</param>
        /// <returns>返回整型数字</returns>
        public static int GenerateRandomInteger(int min = 0, int max = 2147483647)
        {
            var randomNumberBuffer = new byte[10];
            new RNGCryptoServiceProvider().GetBytes(randomNumberBuffer);
            return new Random(BitConverter.ToInt32(randomNumberBuffer, 0)).Next(min, max);
        }

        /// <summary>
        /// 确保一个字符串不超过最大允许的长度
        /// </summary>
        /// <param name="str">输入字符串</param>
        /// <param name="maxLength">最大长度</param>
        /// <returns>输入的字符串如果长度在最大长度内，则返回原字符串，否则截断输入字符串</returns>
        public static string EnsureMaximumLength(string str, int maxLength)
        {
            if (String.IsNullOrEmpty(str))
                return str;

            return str.Length > maxLength ? str.Substring(0, maxLength) : str;
        }

        /// <summary>
        /// 确保一个字符串仅含数值
        /// </summary>
        /// <param name="str">输入字符串</param>
        /// <returns>如果输入为null 或为空的，则返回空</returns>
        public static string EnsureNumericOnly(string str)
        {
            if (String.IsNullOrEmpty(str))
                return string.Empty;

            var result = new StringBuilder();
            foreach (char c in str)
            {
                if (Char.IsDigit(c))
                    result.Append(c);
            }
            return result.ToString();
        }

        /// <summary>
        /// 确保字符串不为null
        /// </summary>
        /// <param name="str">Input string</param>
        /// <returns>Result</returns>
        public static string EnsureNotNull(string str)
        {
            if (str == null)
                return string.Empty;

            return str;
        }

        /// <summary>
        /// 显示指定的字符串数据是否空或空串
        /// </summary>
        /// <param name="stringsToValidate">要验证的数组对象</param>
        /// <returns>返回true或者false</returns>
        public static bool AreNullOrEmpty(params string[] stringsToValidate)
        {
            bool result = false;
            Array.ForEach(stringsToValidate, str =>
            {
                if (string.IsNullOrEmpty(str)) result = true;
            });
            return result;
        }


        private static AspNetHostingPermissionLevel? _trustLevel;
        /// <summary>
        /// Finds the trust level of the running application (http://blogs.msdn.com/dmitryr/archive/2007/01/23/finding-out-the-current-trust-level-in-asp-net.aspx)
        /// </summary>
        /// <returns>The current trust level.</returns>
        public static AspNetHostingPermissionLevel GetTrustLevel()
        {
            if (!_trustLevel.HasValue)
            {
                //set minimum
                _trustLevel = AspNetHostingPermissionLevel.None;

                //determine maximum
                foreach (AspNetHostingPermissionLevel trustLevel in
                        new[] {
                                AspNetHostingPermissionLevel.Unrestricted,
                                AspNetHostingPermissionLevel.High,
                                AspNetHostingPermissionLevel.Medium,
                                AspNetHostingPermissionLevel.Low,
                                AspNetHostingPermissionLevel.Minimal 
                            })
                {
                    try
                    {
                        new AspNetHostingPermission(trustLevel).Demand();
                        _trustLevel = trustLevel;
                        break; //we've set the highest permission we can
                    }
                    catch (System.Security.SecurityException)
                    {
                    }
                }
            }
            return _trustLevel.Value;
        }

        /// <summary>
        /// 给一个对性的属性赋值
        /// </summary>
        /// <param name="instance">要设置的对象实例</param>
        /// <param name="propertyName">对象的属性</param>
        /// <param name="value">设置的值</param>
        public static void SetProperty(object instance, string propertyName, object value)
        {
            if (instance == null) throw new ArgumentNullException("instance");
            if (propertyName == null) throw new ArgumentNullException("propertyName");

            Type instanceType = instance.GetType();
            PropertyInfo pi = instanceType.GetProperty(propertyName);

            //Gtodo:
            //if (pi == null)
            //    throw new Web7Exception(new LocalizedString(string.Format("No property '{0}' found on the instance of type '{1}'.", propertyName, instanceType)));
            //if (!pi.CanWrite)
            //    throw new Web7Exception(new LocalizedString(string.Format("The property '{0}' on the instance of type '{1}' does not have a setter.", propertyName, instanceType)));
            if (value != null && !value.GetType().IsAssignableFrom(pi.PropertyType))
                value = To(value, pi.PropertyType);
            pi.SetValue(instance, value, new object[0]);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static TypeConverter GetCustomTypeConverter(Type type)
        {
            //we can't use the following code in order to register our custom type descriptors
            //TypeDescriptor.AddAttributes(typeof(List<int>), new TypeConverterAttribute(typeof(GenericListTypeConverter<int>)));
            //so we do it manually here

            if (type == typeof(List<int>))
                return new GenericListTypeConverter<int>();
            if (type == typeof(List<decimal>))
                return new GenericListTypeConverter<decimal>();
            if (type == typeof(List<string>))
                return new GenericListTypeConverter<string>();

            return TypeDescriptor.GetConverter(type);
        }

        /// <summary>
        /// 将一个值类型转化为对象类型
        /// </summary>
        /// <param name="value">要转化的值类型</param>
        /// <param name="destinationType">目标对象类型</param>
        /// <returns>转化后的对象类型</returns>
        public static object To(object value, Type destinationType)
        {
            return To(value, destinationType, CultureInfo.InvariantCulture);
        }

        /// <summary>
        /// 将一个值类型转化为对象类型
        /// </summary>
        /// <param name="value">要转化的值类型</param>
        /// <param name="destinationType">目标对象类型</param>
        /// <param name="culture">Culture</param>
        /// <returns>The converted value.</returns>
        public static object To(object value, Type destinationType, CultureInfo culture)
        {
            if (value != null)
            {
                var sourceType = value.GetType();

                TypeConverter destinationConverter = GetCustomTypeConverter(destinationType);
                TypeConverter sourceConverter = GetCustomTypeConverter(sourceType);
                if (destinationConverter != null && destinationConverter.CanConvertFrom(value.GetType()))
                    return destinationConverter.ConvertFrom(null, culture, value);
                if (sourceConverter != null && sourceConverter.CanConvertTo(destinationType))
                    return sourceConverter.ConvertTo(null, culture, value, destinationType);
                if (destinationType.IsEnum && value is int)
                    return Enum.ToObject(destinationType, (int)value);
                if (!destinationType.IsInstanceOfType(value))
                    return Convert.ChangeType(value, destinationType, culture);
            }
            return value;
        }

        /// <summary>
        /// 将一个值类型转化为对象类型
        /// </summary>
        /// <param name="value">The value to convert.</param>
        /// <typeparam name="T">The type to convert the value to.</typeparam>
        /// <returns>The converted value.</returns>
        public static T To<T>(object value)
        {
            //return (T)Convert.ChangeType(value, typeof(T), CultureInfo.InvariantCulture);
            return (T)To(value, typeof(T));
        }

        /// <summary>
        /// 转换为前端枚举
        /// </summary>
        /// <param name="str">输入字符串</param>
        /// <returns>Converted string</returns>
        public static string ConvertEnum(string str)
        {
            string result = string.Empty;
            char[] letters = str.ToCharArray();
            foreach (char c in letters)
                if (c.ToString(CultureInfo.InvariantCulture) != c.ToString(CultureInfo.InvariantCulture).ToLower())
                    result += " " + c.ToString(CultureInfo.InvariantCulture);
                else
                    result += c.ToString(CultureInfo.InvariantCulture);
            return result;
        }
    }
}
